package com.File;

import org.junit.Test;

import java.io.*;

/**
 * 一.流的分类:
 * 1.操作数据单位不同:字节流，字符流
 * 2.数据的查询:输入流，输出流
 * 3.流的角色: 节点流，处理流
 * <p>
 * <p>
 * 二.流的体系结构
 * 抽象基类                       节点流                                      缓冲流(处理流的一种)
 * InputStream                 FileInputStream                              BufferedInputStream
 * OutputStream                FileOutputStream                             BufferedOutputStream
 * Reader                      FileReader                                   BufferedReader
 * Writer                      FileWriter                                   BufferedWriter
 */

/**
 * 说明点:
 * 1.read()的理解: 返回读入的一个字符，如果达到文件的末尾，返回-1
 * 2.异常的处理，为了保证流资源一定可以保证执行关闭操作。需要使用try-catch-final来处理\
 * 3.读入的文件一定要存在，否则就会报FileNotFoundException。
 */
public class FileReaderWriterTest {

    public static void main(String[] args) {
        File file = new File("hello.txt");// 相较于当前的方法
        System.out.println(file.getAbsolutePath());
    }


    /**
     * 将day09下的hello.txt文件内容读入程序中，输出到控制台
     */
    @Test
    public void testFileReader() {
        //1.实例化File对象，指明我们要操作的文件
        File file = new File("hello.txt"); //相较于当前的Module

        //2.提供具体的流
        FileReader fileReader = null;
        try {
            fileReader = new FileReader(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        //3.数据的读入
        //read():返回读入的一个字符，如果达到文件的末尾，返回-1
        //方式一:
//        int read = fileReader.read();
//        while (read != -1){
//            System.out.println((char)read);
//            read = fileReader.read();
//        }
        //方式二: 语法上针对方式一的修改
        int data;
        while (true) {
            try {
                if (!((data = fileReader.read()) != -1)) break;
                System.out.println((char) data);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //4.流的关闭操作,因为JVM提供了一个垃圾回收机制，但是垃圾回收对数据库连接，输入输出流，Socket连接无能为力。
                //程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收，会有一些效果，但是系统是否进行垃圾回收仍然不确定。
                try {
                    if (fileReader != null)
                        fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    //对read()操作升级:使用read的重载方法
    @Test
    public void testFileReader1() throws IOException {
        //1.File类的实例化
        File file = new File("D:\\xuehujavaSE01\\src\\main\\java\\com\\day18\\hello.txt");

        //2.FileReader流的实例化
        FileReader fileReader = new FileReader(file);

        //3.读入的操作系统
        //每次读取5个字符//read(char[] cbuf):返回每次读入cbuf数组的字符的个数。如果达到文件末尾，返回-1
        char[] cbuf = new char[5];
        int len;
        while ((len = fileReader.read(cbuf)) != -1) {
            //方式二:
            //错误的写法
//            for (int i = 0; i < cbuf.length; i++){
//                System.out.print(cbuf[i]);
//            }
            for (int i = 0; i < len; i++) {
                System.out.println(cbuf[i]);
            }

            //方式二:
            //错误的写法,对应着方式一的错误写法
            String str = new String(cbuf);
            System.out.println(str);
            //正确的写法
            String string = new String(cbuf, 0, len);
            System.out.println(string);


        }


        //4.资源的关闭
        if (fileReader != null)
            fileReader.close();
    }


    /**
     * 从内存中写出数据到硬盘的文件中
     * 说明：
     * 1.输出操作，对应的file是可以不存在的，如果不存在在输出的过程中，会自动创建此文件。
     * 2.如果存在，对原有文件的一个覆盖
     * 3.如果File对应的文件，如果不存在，在输出的过程中，会自动创建文件，
     * 如果存在:
     *  如果流使用的构造器是:FileWriter(file,false) / FileWriter(file);对原有文件的覆盖。
     *  如果流使用的构造器是: FileWirter(file,true) :不会对原有文件进行覆盖，只会在原有的内容基础上进行追加
     *  关于流的异常处理，尽量使用try-catch-finally
     *
     */

    @Test
    public void testFileWriter() {
        //1.提供File类的对象，指明写出到的文件。
        File file = new File("D:\\xuehujavaSE01\\src\\main\\java\\com\\day18\\hello.txt");

        //2.提供FileWriter的对象，用于数据的写出,false表示不在原有的文件的内容上追加，进行覆盖，如果是true就是追加
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(file, false);
            //3.写出的具体操作
            fileWriter.write("I have a dream!\n");
            fileWriter.write("you need to have a dream!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.流资源的关闭操作
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }


    }


    //    使用FileReader和FileWriter实现文件的读入和写出。
    @Test
    public void testFileReaderFileWriter() {
        FileReader fileReader = null;
        FileWriter fileWriter = null;
        try {
            //1.创建File类的对象，指明读入和写出的文件
            File srcFile = new File("D:\\xuehujavaSE01\\src\\main\\java\\com\\File\\hello.txt");
            File destFile = new File("D:\\xuehujavaSE01\\src\\main\\java\\com\\File\\hello2.txt");


            //2.创键输入流和输出流的对象
            fileReader = new FileReader(srcFile);
            fileWriter = new FileWriter(destFile);

            //3.数据的读入和写出操作
            char[] cbuf = new char[5];
            int len; //记录每次读入到cbuf数组中的字符个数
            while ((len = fileReader.read(cbuf)) != -1) {
    //            每次写出len个字符
                fileWriter.write(cbuf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileReader != null || fileWriter != null){
                //4.关闭流资源
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }


//    不能使用字符流处理图片等字节数据。




}
